package priv.conceit.sc.hoxton.file.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import priv.conceit.sc.hoxton.common.constant.file.FileSourceEnum;
import priv.conceit.sc.hoxton.common.entity.file.dto.FilePathDTO;
import priv.conceit.sc.hoxton.common.entity.file.dto.FilePreviewDTO;
import priv.conceit.sc.hoxton.common.entity.file.pojo.File;
import priv.conceit.sc.hoxton.common.entity.file.qo.FileUploadQO;
import priv.conceit.sc.hoxton.common.util.FileSuffixUtil;
import priv.conceit.sc.hoxton.common.util.FileUtil;
import priv.conceit.sc.hoxton.common.util.StorageCapacityUtil;
import priv.conceit.sc.hoxton.common.web.WebResponse;
import priv.conceit.sc.hoxton.file.config.FileProperties;
import priv.conceit.sc.hoxton.file.dao.FileMapper;
import priv.conceit.sc.hoxton.file.handle.source.AbsSourceHandle;
import priv.conceit.sc.hoxton.file.handle.source.SourceHandleFactory;
import priv.conceit.sc.hoxton.file.service.FileService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author conceit
 * @date 2020/4/27 14:56
 */
@Service
@Slf4j
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Autowired
    FileProperties fileProperties;

    @Autowired
    SourceHandleFactory sourceHandleFactory;



    /**
     * 文件上传
     *
     * @param fileUploadQO
     * @return int
     * @author conceit
     * @date 2020/4/27 15:30
     */
    @Override
    public List<String> upload(FileUploadQO fileUploadQO) {
        //具体使用哪一种存储方式
        FileSourceEnum fileSourceEnum=null;
        if(Objects.isNull(fileUploadQO.getFileSourceKey())){
            fileSourceEnum=fileProperties.getSource().getPrimary();
        }
        else{
            fileSourceEnum=FileSourceEnum.getByKey(fileUploadQO.getFileSourceKey());
        }
        AbsSourceHandle absSourceHandle =sourceHandleFactory.create(fileSourceEnum);

        List<MultipartFile> files = fileUploadQO.getFiles();
        if (!FileUtil.hasUploadFile(files)) {
            //todo exception
            throw new NullPointerException();
        }
        //文件类型是否合规
        List<String> noneMatchFileName=FileSuffixUtil.callNoneMatchFileName(fileProperties.getUpload().merge,FileUtil.getFileNames(fileUploadQO.getFiles()),fileProperties.getUpload().getIgnoreCase());
        if(CollUtil.isNotEmpty(noneMatchFileName)){
            throw new IllegalArgumentException(noneMatchFileName.toString());
        }

        List<String> result=new ArrayList<>();
        for (MultipartFile file : files) {
            FilePathDTO fileDetail;
            try {
                fileDetail = absSourceHandle.upload(file);
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
            File fileDB =new File();
            fileDB.setSuffix(FileUtil.getFileSuffix(file.getOriginalFilename()));
            fileDB.setContentType(file.getContentType());
            fileDB.setSourceKey(fileSourceEnum.getKey());
            fileDB.setSize(file.getSize());
            fileDB.setSizeUnit(StorageCapacityUtil.StorageCapacityUnitEnum.B.name());
            fileDB.setOriginalName(file.getOriginalFilename());
            fileDB.setSavedName(fileDetail.getSavedFileName());
            fileDB.setShortCode(fileDetail.getShortCode());
            fileDB.setCreateUserId(fileUploadQO.getCreateUserId());
            fileDB.setCreateTime(LocalDateTime.now());
            this.save(fileDB);
            result.add(fileDetail.getShortCode());
        }

        return result;
    }

    
    /** 
     * download 下载
     * 
     * @param shortCode 资源短码
     * @return org.springframework.http.ResponseEntity
     * @author conceit
     * @date 2020/4/28 9:33
     */
    @Override
    public ResponseEntity download (String shortCode) throws Exception{
        LambdaQueryWrapper<File> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<File> eq = lambdaQueryWrapper.eq(File::getShortCode, shortCode);
        File file= this.getOne(eq);

        if(Objects.isNull(file)){
            // todo 业务异常
            throw new NullPointerException();
        }
        AbsSourceHandle absSourceHandle = sourceHandleFactory.create(FileSourceEnum.getByKey(file.getSourceKey()));
        byte[] bytes= absSourceHandle.download(file.getSavedName());
        ResponseEntity responseEntity=FileUtil.buildDownload(file.getOriginalName(),bytes,
                MediaType.APPLICATION_OCTET_STREAM, HttpStatus.OK,
                fileProperties.getDownload().getFileNameEncoder());
        return responseEntity;
    }

    /**
     * share 分享
     *
     * @param shortCode 文件短编码
     * @return priv.conceit.sc.hoxton.common.util.RestfulResponse
     * @author conceit
     * @date 2020/4/28 9:33
     */
    @Override
    public WebResponse share(String shortCode) {
        return null;
    }

    /**
     * preview 预览
     *
     * @param  shortCode 文件短编码
     * @return org.springframework.http.ResponseEntity
     * @author conceit
     * @date 2020/4/28 9:33
     */
    @Override
    public ResponseEntity preview(String shortCode) {
        LambdaQueryWrapper<File> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(File::getShortCode, shortCode);
        File file= this.getOne(lambdaQueryWrapper);
        if(Objects.isNull(file)){
            // todo 业务异常
            throw new NullPointerException();
        }
        AbsSourceHandle absSourceHandle = sourceHandleFactory.create(FileSourceEnum.getByKey(file.getSourceKey()));
        FilePreviewDTO filePreviewDetail= null;
        try {
            filePreviewDetail = absSourceHandle.preview(file.getSavedName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(filePreviewDetail.getContentType()));
        return  ResponseEntity.status(HttpStatus.OK).headers(headers).body(filePreviewDetail.getBytes());
    }

    /**
     * del 删除
     *
     * @param  shortCode 文件短编码
     * @return priv.conceit.sc.hoxton.common.util.RestfulResponse
     * @author conceit
     * @date 2020/4/28 9:34
     */
    @Override
    @SuppressWarnings("ALL")
    public boolean del(String shortCode) {
        LambdaQueryWrapper<File> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(File::getShortCode, shortCode);
        File file= this.getOne(lambdaQueryWrapper);
        if(Objects.isNull(file)){
            // todo 业务异常
            throw new NullPointerException();
        }
        AbsSourceHandle absSourceHandle = sourceHandleFactory.create(FileSourceEnum.getByKey(file.getSourceKey()));
        boolean flag= false;
        try {
            flag = absSourceHandle.del(file.getSavedName());
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.FALSE;
        }
        if(flag){
            return this.removeById(file.getId());
        }

        return Boolean.FALSE;
    }


}
